#include "node.h"
#include "scenegraph.h"
#include "../../core/resources/resourcemanager.h"

namespace gunsmith
{
CNode::CNode(ENODETYPE eType)
{
	m_eNodeType		= eType;
	m_pParent		= NULL;
	m_pPrevSibbling	= NULL;
	m_pNextSibbling	= NULL;
	m_pFirstChild	= NULL;
	m_pSceneGraph	= NULL;
	m_sName			= "";
	m_pResMngr		= CResourceManager::GetInstance();
}

CNode::~CNode()
{
	m_pResMngr->Release();
}

/*!	\brief		Adds a child to the node. (see remarks)
	\param		pNewChild	Child node.
	\return		void
	\remarks	Will become last sibbling according to first child.
	\sa			*/
void CNode::AddChild(CNode* pNewChild)
{
	if(this->m_pFirstChild)								// got first child:
		this->m_pFirstChild->AddSibbling(pNewChild);	// add sibbling to first child
	else												// no first child:
	{
		pNewChild->m_pParent = this;					// (new)->parent = this
		this->m_pFirstChild = pNewChild;				// (first) = (new)
		pNewChild->SetSceneGraph(m_pSceneGraph);
	}
}

/*!	\brief		Adds a sibbling as last sibbling to the node.
	\param		pNewSibbling
	\return		void
	\remarks	
	\sa			*/
void CNode::AddSibbling(CNode* pNewSibbling)
{
	pNewSibbling->SetSceneGraph(m_pSceneGraph);
	CNode *pLastSibbling = GetLastSibbling();			// retrieve last sibbling
	
	pNewSibbling->m_pParent = this->m_pParent;			// assign parent node
	pNewSibbling->m_pPrevSibbling = pLastSibbling;		// new sibbling's prev node points to the (former) last sibbling
	if(pLastSibbling)									// if there's a last sibbling...
		pLastSibbling->m_pNextSibbling = pNewSibbling;	// ...last sibbling's next node points to the new sibbling 
}

/*!	\brief		Returns the first child.
	\return		CNode*	First child.
	\remarks	
	\sa			*/
CNode* CNode::GetFirstChild() const
{
	return m_pFirstChild;
}

/*!	\brief		Returns the previous sibbling.
	\return		CNode* Previous sibbling.
	\remarks	
	\sa			*/
CNode* CNode::GetPrevSibbling() const
{
	return m_pPrevSibbling;
}

/*!	\brief		Returns the next sibblig.
	\return		CNode* Next sibbling.
	\remarks	
	\sa			*/
CNode* CNode::GetNextSibbling() const
{
	return m_pNextSibbling;
}

/*!	\brief		Returns the parent node.
	\return		CNode*	Parent node.
	\remarks	
	\sa			*/
CNode* CNode::GetParent() const
{
	return m_pParent;
}

/*!	\brief		Returns the type of the node.
	\return		ENODETYPE
	\remarks	
	\sa			*/
ENODETYPE CNode::GetNodeType() const
{
	return m_eNodeType;
}

/*!	\brief		Sets the name of the node.
	\param		sName	Node name.
	\return		void
	\remarks	
	\sa			*/
void CNode::SetName(const string& sName)
{
	m_sName = sName;
}

/*!	\brief		Removes the node from the graph and all its children. (see remarks)
	\param		ppNode	Node to remove.
	\return		void
	\remarks	Node pointer will become NULL on removal.
	\sa			*/
void CNode::Remove(CNode **ppNode)
{
	if(*ppNode == NULL)
		return;

	CNode *pCurrentNode = *ppNode;

	CNode *pParent			= pCurrentNode->m_pParent;
	CNode *pNextSibbling	= pCurrentNode->m_pNextSibbling;
	CNode *pPrevSibbling	= pCurrentNode->m_pPrevSibbling;

	RemoveRecursive(pCurrentNode);

	// assign new pointer directions
	if(pPrevSibbling)
		pPrevSibbling->m_pNextSibbling = pNextSibbling;
	else
		if(pParent)
			pParent->m_pFirstChild = pNextSibbling;
		
	if(pNextSibbling)
		pNextSibbling->m_pPrevSibbling = m_pPrevSibbling;


	// if attached to scene graph notify scene graph that it needs to update
	if(m_pSceneGraph)
	{
		m_pSceneGraph->m_bNeedToUpdate = true;

		// check if current node is scene graphs root node
		if(pCurrentNode == m_pSceneGraph->m_pNodeRoot)
			m_pSceneGraph->m_pNodeRoot = NULL;
	}

	//delete pCurrentNode;
	*ppNode = NULL;
}

/*!	\brief		Updates the node according to the delta time and data provided. (see remarks)
	\param		fDelta	Delta time.
	\param		pData	Additional data.
	\return		void
	\remarks	Needs to be implemented by deriving node classes that need to update data freequently.
	\sa			*/
void CNode::Update(float fDelta, void *pData)
{

}

/*!	\brief		Returns last sibbling.
	\return		CNode*	Last siblling.
	\remarks	
	\sa			*/
CNode* CNode::GetLastSibbling() const
{
	CNode *pLastSibbling = (CNode*)this;

	while(pLastSibbling->m_pNextSibbling)				// as long as we have a next...							
		pLastSibbling = pLastSibbling->m_pNextSibbling;	// ...traverse through all sibblings

	return pLastSibbling;
}

/*!	\brief		Removes nodes revursivly.
	\param		pNode	Current node.
	\return		void
	\remarks	
	\sa			*/
void CNode::RemoveRecursive(CNode *pNode)
{
	if(pNode == NULL)
		return;

	RemoveRecursive(pNode->m_pNextSibbling);
	RemoveRecursive(pNode->m_pFirstChild);

	delete pNode;
}

/*!	\brief		Draw node.
	\return		void
	\remarks	
	\sa			*/
void CNode::Draw()
{

}

/*!	\brief		Returns the name of the node.
	\return		const char*
	\remarks	
	\sa			*/
const char* CNode::GetName() const
{
	return m_sName.c_str();
}

/*!	\brief		Prints the structure of a base node recursivly. (see remarks)
	\param		pNodeBase	Base node.
	\param		sIndention	Idention of the nodes (shoudl be "" initially).
	\return		void
	\remarks	Can be used to debug and should only be called for that purpose.
	\sa			*/
void CNode::PrintNodeStructure(CNode *pNodeBase, std::string sIndention) const
{
	if(!pNodeBase)
		return;

	printf("%sNode: %s\n", sIndention.c_str(), pNodeBase->GetName());
	PrintNodeStructure(pNodeBase->GetNextSibbling(), sIndention);
	PrintNodeStructure(pNodeBase->GetFirstChild(), sIndention+"+---");
}

/*!	\brief		Gets called instead of Draw() if scene graph enabled debug output.
	\return		void
	\remarks	
	\sa			*/
void CNode::DrawDebug()
{
	Draw();
}

void CNode::SetSceneGraph(CSceneGraph *pSceneGraph)
{
	m_pSceneGraph = pSceneGraph;
}
};